#!/usr/bin/env python3

__author__ = 'z.Wick.Tone.Burst'
__doc__ = """ Basic utils for ML."""


import numpy as np
import random



def load_data(path):
    data = []
    with open(path, 'r') as f:
        lines = f.readlines()
    for line in lines:
        l = line.split()
        x, y = list(map(float, l[:-1])), int(l[-1])
        data.append((x, y))
    return data


def randomize(dset):
    """Move it to toolz."""
    seed = random.randint(0, len(dset) - 1)
    return dset[seed:] + dset[:seed]



def transform():
    pass



# package prettify
class Prettify:
    def clean(self):
        pass
    def prune(self):
        pass
    def hint(self):
        """Adding Virtual Examples."""
        pass
    def regularizer(self):
        """Target-dependence, Plausible, Friendly (Alike the Error Measure)."""
        pass


# package ?!
class Regularizer:
    # L1, L2
    def L1(self, W, C):
        """Convex, not differentiable, everywhere, sparsity in solution."""
        return np.sum(W * W) <= C

    def L2(self, W, C):
        """Convex, differentiable everywhere, easy to optimize."""
        return np.sub(np.abs(W)) <= C


# Error
# Omega



class MLData(object):
    @staticmethod
    def initialize(D, X, Y):
        D.X = np.array(X)
        D.Y = np.array(Y)


    def __init__(self, path=None):
        if not path:
            _X = (0, 0)
            _Y = 0
        else:
            _X = []; _Y = []
            with open(path, 'r') as f:
                lines = f.readlines()
            for line in lines:
                l = line.split()
                x, y = [1, ] + list(map(float, l[:-1])), int(l[-1])
                _X.append(x)
                _Y.append(y)
        MLData.initialize(self, _X, _Y)


    def __len__(self):
        return self.size


    def choice(self, i=None):
        if not i:
            i = random.randint(0, self.size - 1)
        i %= self.size
        return self.X[i], self.Y[i]


    @property
    def size(self):
        return self.X.shape[0]

    @property
    def xdim(self):
        return self.X.shape[1]

    @property
    def pure(self):
        return self.X[..., 1:], self.Y
